﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace DotNet.Common.Extensions.Random
{
    /// <summary>
    /// 伪随机数生成器扩展方法
    /// </summary>
    public static class RandomExtensions
    {
        /// <summary>
        /// 随机返回布尔值
        /// </summary>
        /// <param name="random"></param>
        /// <returns></returns>
        public static bool NextBool(this System.Random random)
        {
            return random.NextDouble() > 0.5;
        }

        /// <summary>
        /// 随机返回枚举值
        /// </summary>
        /// <typeparam name="T">枚举值类型</typeparam>
        /// <param name="random"></param>
        /// <returns></returns>
        public static T NextEnum<T>(this System.Random random) where T : struct
        {
            Type type = typeof(T);
            if (type.IsEnum == false) throw new InvalidOperationException();

            var array = Enum.GetValues(type);
            var index = random.Next(array.GetLowerBound(0), array.GetUpperBound(0) + 1);
            return (T)array.GetValue(index);
        }

        /// <summary>
        ///   用随机数填充指定字节数组的元素。
        /// </summary>
        /// <param name="random"></param>
        /// <param name="length">字节数组长度</param>
        /// <returns></returns>
        public static byte[] NextBytes(this System.Random random, int length)
        {
            var data = new byte[length];
            random.NextBytes(data);
            return data;
        }

        /// <summary>
        /// 返回隨機不重複數組
        /// </summary>
        /// <param name="rnd"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static IEnumerable<int> NextUnique(this System.Random rnd, int start, int count)
        {
            long num = (long)start + (long)count - 1L;
            if (count < 0 || num > 2147483647L)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            List<int> candidates = Enumerable.Range(start, count).ToList();

            while (candidates.Any())
            {
                int index = rnd.Next(candidates.Count);
                yield return candidates[index];
                candidates.RemoveAt(index);
            }
        }

        /// <summary>
        /// 數據源中隨機返回一部份數據
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="rnd"></param>
        /// <param name="source"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static IEnumerable<TSource> NextUnique<TSource>(this System.Random rnd, IList<TSource> source, int count)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            List<int> candidates = Enumerable.Range(0, source.Count).ToList();
            for (int i = 0; i < count || i < source.Count; i++)
            {
                int index = rnd.Next(candidates.Count);
                yield return source[index];
                candidates.RemoveAt(index);
            }
        }
    }
}
